using System;
using System.Collections.Generic;
using System.Linq;
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Audio;
using Microsoft.Xna.Framework.Content;
using Microsoft.Xna.Framework.GamerServices;
using Microsoft.Xna.Framework.Graphics;
using Microsoft.Xna.Framework.Input;
using Microsoft.Xna.Framework.Media;

namespace LightSystemTest
{
    /// <summary>
    /// This is the main type for your game
    /// </summary>
    public class Game1 : Microsoft.Xna.Framework.Game
    {
        GraphicsDeviceManager graphics;
        SpriteBatch spriteBatch;

        Texture2D Background;
        Texture2D MidGround;

        List<PointLight> pointLightHandles;
        List<SpotLight> spotLightHandles;

        public LightRenderer lightSystem;

        public Game1()
        {
            graphics = new GraphicsDeviceManager(this);
            graphics.PreferredBackBufferWidth = 1280;
            graphics.PreferredBackBufferHeight = 720;
            Content.RootDirectory = "Content";

            spotLightHandles = new List<SpotLight>();

            lightSystem = new LightRenderer(graphics);
        }

        /// <summary>
        /// Allows the game to perform any initialization it needs to before starting to run.
        /// This is where it can query for any required services and load any non-graphic
        /// related content.  Calling base.Initialize will enumerate through any components
        /// and initialize them as well.
        /// </summary>
        protected override void Initialize()
        {
            lightSystem.Initialize();
            lightSystem.minLight = 0.5f;
            lightSystem.lightBias = 3f;

            spotLightHandles.Add(new SpotLight(new Vector2(GraphicsDevice.Viewport.Width / 2f, GraphicsDevice.Viewport.Height / 2f), Vector2.UnitY * 1.0001f, 0.8f, 1.5f, 1.25f, 500f, Color.Blue));
            spotLightHandles.Add(new SpotLight(new Vector2((GraphicsDevice.Viewport.Width / 2f) + 100, (GraphicsDevice.Viewport.Height / 2f) + 100), Vector2.UnitY * -1.0001f, 0.8f, 1.5f, 1.25f, 500f, Color.Red));

            lightSystem.spotLights.Add(spotLightHandles[0]);
            lightSystem.spotLights.Add(spotLightHandles[1]);
            //lightSystem.pointLights.Add(new PointLight(new Vector2(GraphicsDevice.Viewport.Width / 2f, GraphicsDevice.Viewport.Height / 2f), 0.8f, 500f, Color.White));
            base.Initialize();
        }

        /// <summary>
        /// LoadContent will be called once per game and is the place to load
        /// all of your content.
        /// </summary>
        protected override void LoadContent()
        {
            spriteBatch = new SpriteBatch(GraphicsDevice);

            Background = Content.Load<Texture2D>(@"Textures\Background");
            MidGround = Content.Load<Texture2D>(@"Textures\Midground");
            
            lightSystem.LoadContent(Content);
        }

        /// <summary>
        /// UnloadContent will be called once per game and is the place to unload
        /// all content.
        /// </summary>
        protected override void UnloadContent()
        {
            // TODO: Unload any non ContentManager content here
        }

        /// <summary>
        /// Allows the game to run logic such as updating the world,
        /// checking for collisions, gathering input, and playing audio.
        /// </summary>
        /// <param name="gameTime">Provides a snapshot of timing values.</param>
        protected override void Update(GameTime gameTime)
        {
            // Allows the game to exit
            if (GamePad.GetState(PlayerIndex.One).Buttons.Back == ButtonState.Pressed)
                this.Exit();

            if (GamePad.GetState(PlayerIndex.One).ThumbSticks.Left.X < -0.25f)
            {
                spotLightHandles[0].Position.X -= 0.25f * gameTime.ElapsedGameTime.Milliseconds;
                if (spotLightHandles[0].Position.X < 0)
                    spotLightHandles[0].Position.X = 0;
            }
            else if (GamePad.GetState(PlayerIndex.One).ThumbSticks.Left.X > 0.25f)
            {
                spotLightHandles[0].Position.X += 0.25f * gameTime.ElapsedGameTime.Milliseconds;
                if (spotLightHandles[0].Position.X > GraphicsDevice.Viewport.Width)
                    spotLightHandles[0].Position.X = GraphicsDevice.Viewport.Width;
            }
            else if (GamePad.GetState(PlayerIndex.One).ThumbSticks.Left.Y > 0.25f)
            {
                spotLightHandles[0].Position.Y -= 0.25f * gameTime.ElapsedGameTime.Milliseconds;
                if (spotLightHandles[0].Position.Y < 0)
                    spotLightHandles[0].Position.Y = 0;
            }
            else if (GamePad.GetState(PlayerIndex.One).ThumbSticks.Left.Y < -0.25f)
            {
                spotLightHandles[0].Position.Y += 0.25f * gameTime.ElapsedGameTime.Milliseconds;
                if (spotLightHandles[0].Position.Y > GraphicsDevice.Viewport.Height)
                    spotLightHandles[0].Position.Y = GraphicsDevice.Viewport.Height;
            }

            if (GamePad.GetState(PlayerIndex.One).Buttons.A == ButtonState.Pressed)
            {
                spotLightHandles[0].direction = Vector2.Transform(spotLightHandles[0].direction, Quaternion.CreateFromAxisAngle(Vector3.UnitZ, 0.0015f * gameTime.ElapsedGameTime.Milliseconds));
            }

            if (GamePad.GetState(PlayerIndex.One).ThumbSticks.Right.X < -0.25f)
            {
                spotLightHandles[1].Position.X -= 0.25f * gameTime.ElapsedGameTime.Milliseconds;
                if (spotLightHandles[1].Position.X < 0)
                    spotLightHandles[1].Position.X = 0;
            }
            else if (GamePad.GetState(PlayerIndex.One).ThumbSticks.Right.X > 0.25f)
            {
                spotLightHandles[1].Position.X += 0.25f * gameTime.ElapsedGameTime.Milliseconds;
                if (spotLightHandles[1].Position.X > GraphicsDevice.Viewport.Width)
                    spotLightHandles[1].Position.X = GraphicsDevice.Viewport.Width;
            }
            else if (GamePad.GetState(PlayerIndex.One).ThumbSticks.Right.Y > 0.25f)
            {
                spotLightHandles[1].Position.Y -= 0.25f * gameTime.ElapsedGameTime.Milliseconds;
                if (spotLightHandles[1].Position.Y < 0)
                    spotLightHandles[1].Position.Y = 0;
            }
            else if (GamePad.GetState(PlayerIndex.One).ThumbSticks.Right.Y < -0.25f)
            {
                spotLightHandles[1].Position.Y += 0.25f * gameTime.ElapsedGameTime.Milliseconds;
                if (spotLightHandles[1].Position.Y > GraphicsDevice.Viewport.Height)
                    spotLightHandles[1].Position.Y = GraphicsDevice.Viewport.Height;
            }
            
            if (GamePad.GetState(PlayerIndex.One).Buttons.B == ButtonState.Pressed)
            {
                spotLightHandles[1].direction = Vector2.Transform(spotLightHandles[1].direction, Quaternion.CreateFromAxisAngle(Vector3.UnitZ, 0.0015f * gameTime.ElapsedGameTime.Milliseconds));
            }
            
            base.Update(gameTime);
        }

        /// <summary>
        /// This is called when the game should draw itself.
        /// </summary>
        /// <param name="gameTime">Provides a snapshot of timing values.</param>
        protected override void Draw(GameTime gameTime)
        {

            lightSystem.BeginDrawBackground();
            spriteBatch.Begin();
            spriteBatch.Draw(Background, new Rectangle(0, 0, GraphicsDevice.Viewport.Width, GraphicsDevice.Viewport.Height), Color.White);
            spriteBatch.End();
            lightSystem.EndDrawBackground();

            lightSystem.BeginDrawShadowCasters();
            spriteBatch.Begin();
            spriteBatch.Draw(MidGround, new Rectangle(0, 0, GraphicsDevice.Viewport.Width, GraphicsDevice.Viewport.Height), Color.White);
            spriteBatch.End();
            lightSystem.EndDrawShadowCasters();

            lightSystem.DrawLitScene();

            //Draw any foreground sprites here.

            base.Draw(gameTime);
        }
    }
}
